########################################
使用 Systemd Timer 调度任务
########################################
.. admonition:: 注
本文是 `Systemd Timers for Scheduling Tasks - Fedora Magazine `_ 的翻译
Systemd 提供 timer 已经有一段时间了,作为 *cron* 的替代品,它值得一试。本篇文章将会告诉你如何使用 *systemd* 中的 timer 在系统启动后重复执行任务。这不是对 systemd 的详细讨论,只是对 timer 组件的介绍。
Cron vs anacron vs systemd:快速查看
****************************************
Cron 可以以几分钟到几个月或更长时间的粒度运行。设置相对简单,只需要一个配置文件,尽管配置略微复杂,但是普通用户也能使用。
但是如果您的系统在任务的特定的时间点上不是开机状态,那么这次任务就会被跳过去
Anacron克服了“系统未运行”的问题。它确保当您的系统再次处于活动状态时将执行任务。虽然它旨在供管理员使用,但某些系统为一般用户提供访问权限。
但是,Anacron 的时间粒度最低是以天为单位。
cron 和 anacron 都有执行上下文必须一致的问题。任务运行时的环境和测试时的环境需要相同,必须提供相同的 shell、环境变量和路径。这意味着测试和调试有时很困难。
Systemd timer 具备 cron 和 anacron 的优秀能力,不仅允许调度粒度精细到分钟,而且允许错过时间点后执行任务。而且可供所有用户使用。
但是配置比较复杂,至少需要两个配置文件。
如果您的 cron 和 anacron 已经配置的很好了,那么可能没有理由去转换代码。但是 systemd 依然值得去研究,因为它可以简化 cron/anacron 的方案。
配置
****************************************
Systemd timer 至少需要两个配置文件:定时器单元和服务单元。对于多行命令,你还需要一个“作业”文件或脚本。
定时器单元定义了调度方式,服务单元定义了执行的人物。有关定时器单元的详细信息,请参阅 :manpage:`systemd.timer` ,对于服务单元的详细信息,参见 :manpage:`systemd.service` 。
单元文件存在于多个位置(在手册页中列出)。然而,对于普通用户而言,最简单的位置是 :file:`~/.config/systemd/user` 。请注意:此处的 “user”是字符串“user”
演示
****************************************
这个演示是一个简单的例子,它创建一个用户调度作业,而不是系统调度作业(以 root 身份运行)。它将消息、日期和时间打印到文件中。
#. 首先创建一个执行任务的脚本,并将其存放到本地的“bin”目录:
::
touch ~/bin/schedule-test.sh
然后添加以下内容到您刚刚创建的文件中:
.. code-block:: bash
#!/bin/sh
echo "This is only a test: $(date)" >> "$HOME/schedule-test-output.txt"
记得给予其执行权。
#. 创建服务单元 :file:`~/.config/systemd/user/schedule-test.service` :
.. code-block:: ini
[Unit]
Description=A job to test the systemd scheduler
[Service]
Type=simple
ExecStart=/home//bin/schedule-test.sh
[Install]
WantedBy=default.target
请注意: 应当是您的 @HOME 地址。但是单元文件路径名中的“user”就是字符串“user”
ExecStart 应当提供的是一个没有变量的绝对地址。但对于用户单元,您可以使用“%h”替换 $HOME 。也就是说,您可以使用::
ExecStart=%h/bin/schedule-test.sh
这只能用于用户单元文件而不是系统单元,因为“%h”在系统环境中始终返回“/root”。其他替换可以在 :manpage:`systemd.unit` 中的“SPECIFIERS”下找到。
#. 创建一个定时器文件 :file:`~/.config/systemd/user/schedule-test.timer` ,它将调度您刚刚创建的服务单元: 。请注意,其与服务单元唯一的区别是拓展名不同。
.. code-block:: ini
[Unit]
Description=Schedule a message every 1 minute
RefuseManualStart=no # Allow manual starts
RefuseManualStop=no # Allow manual stops
[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 minute thereafter
OnUnitActiveSec=60
#File describing job to execute
Unit=schedule-test.service
[Install]
WantedBy=timers.target
注意定时器文件使用“OnUnitActiveSec”指定调度。更灵活的方式是使用“OnCalendar”选项。例如:
.. code-block:: ini
# run on the minute of every minute every hour of every day
OnCalendar=*-*-* *:*:00
# run on the hour of every hour of every day
OnCalendar=*-*-* *:00:00
# run every day
OnCalendar=*-*-* 00:00:00
# run 11:12:13 of the first or fifth day of any month of the year
# 2012, but only if that day is a Thursday or Friday
OnCalendar=Thu,Fri 2012-*-1,5 11:12:13
更多“OnCalendar”相关的信息请看 `这里 `_
#. 所有必要的工作都已经完成了,但是你应当首先测试一下。首先启用用户服务::
$ systemctl --user enable schedule-test.service
这将有以下输出:
::
Created symlink /home//.config/systemd/user/default.target.wants/schedule-test.service → /home//.config/systemd/user/schedule-test.service.
然后进行一次测试::
$ systemctl --user start schedule-test.service
检查您的输出文件($HOME/schedule-test-output.txt)确保你的脚本执行正确无误。
#. 作业正常工作后,我们启用并启动用户计时器::
$ systemctl --user enable --now schedule-test.timer
注意:您在上述步骤中已经启用了服务,因此这里只需要启用定时器即可。
这将产生类似下面的输出:
::
Created symlink /home//.config/systemd/user/timers.target.wants/schedule-test.timer → /home//.config/systemd/user/schedule-test.timer.
其他操作
****************************************
您可以检查和监控服务。如果您收到来自服务单元的错误,下面的第一个命令特别有用:
.. code-block:: bash
$ systemctl --user status schedule-test
$ systemctl --user list-unit-files
手动停止服务::
$ systemctl --user stop schedule-test.service
永久停止和禁用计时器和服务,重新加载守护程序配置并重置任何失败通知:
::
$ systemctl --user stop schedule-test.timer
$ systemctl --user disable schedule-test.timer
$ systemctl --user stop schedule-test.service
$ systemctl --user disable schedule-test.service
$ systemctl --user daemon -reload
$ systemctl --user reset-failed
概括
****************************************
这篇文章将引导您使用systemd计时器,但是,systemd 的内容远不止这里介绍的内容。本文应该为您提供相关的基础。您可以从 `Fedora 杂志 systemd 系列 `_ 开始探索更多相关信息 。
.. seealso::
- :manpage:`systemd.timer`
- :manpage:`systemd.service`
- `使用 Systemd timer 而不是 Cron `_
- `了解和管理 Systemd `_
- 另外,https://opensource.com/ 有一个很好的 `systemd 备忘单 `_